package com.school.springboot_login.service;

import com.school.springboot_login.bean.User;
import com.school.springboot_login.bean.LoginLog;
import com.school.springboot_login.dao.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicInteger;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.security.auth.login.LoginException;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class UserService {
    @Autowired
    private UserDao userDao;
    @Autowired
    private LoginLogDao_redis loginLogRedisDao;
    @Autowired
    private RegisterLogDao registerLogDao;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private LoginLog2Dao loginLog2Dao;

    private static final int FAIL_TIMES = 3;

    private static final String FAIL_KEY = "FAIL:KEY";

    private static final int TIME_INTERVAL = 10;
    private RedisAtomicInteger getRedisCounter(String key) {
        RedisAtomicInteger counter = new RedisAtomicInteger(key, stringRedisTemplate.getConnectionFactory());

        if(counter.get() == 0) {
            counter.expire(TIME_INTERVAL, TimeUnit.MINUTES);
        }
        return counter;
    }

    public UserService()
    {
        System.out.println("UserService");
    }
    @Autowired
    private LoginLogDao loginLogDao;
    public boolean hasMatchUser(String userName, String password){
        int matchCount = userDao.getMatchCount(userName,password);
        //System.out.println(matchCount);
        return matchCount > 0;
    }
    public User findUserByUserName(String userName) {

        return userDao.findUserByUserName(userName);
    }
    //登录成功
    // @Log(moduleName = "用户管理",option = "登录")
    //添加登录事务的注解
    @Transactional(propagation = Propagation.REQUIRED)
    public void loginSuccess(User user) {
        //这段跟书上的不一样
        user.setCredits( 1 + user.getCredits());
        LoginLog loginLog = new LoginLog();
        loginLog.setUserId(user.getUserId());
        loginLog.setIp(user.getLastIp());
        loginLog.setLoginDate(user.getLastVisit());
        userDao.updateLoginInfo(user);
        loginLogDao.insertLoginLog(loginLog);
    }
    //插入用户
    // @Log(moduleName = "用户管理",option = "注册")
    //添加注册事务的注解
    //PROPAGATION_REQUIRED:如果当前没有事务，就新建一个事务，如果已经存在一个事务中，加入到这个事务中。这是最常见的选择。
    //@Transactional(propagation = Propagation.REQUIRED)
    //@Transactional(rollbackFor=Exception.class)，如果类加了这个注解，那么这个类里面的方法抛出异常，就会回滚，数据库里面的数据也会回滚。
    @Transactional(rollbackFor = LoginException.class)
    public void InsertUser(User user)
    {
        //int i=1/0; //验证事务生效

        boolean conUname = false;    // 用户名格式是否正确
        int username_length=user.getUserName().length();
        try {

            if (username_length <=6)
            {
                for (int i = 0;i < username_length;i++)
                {                char ch = user.getUserName().charAt(i);//获取每一个字符
                    if (ch >= 'a' && ch <= 'z') {    // 判断字符是否为a~z的字符
                         conUname = true;    // 设置 conUname 变量值为 true
                    }
                    else {

                        throw new LoginException("用户名中不应该有数字的字符！");
                    }
                }
            } else {
                // 如果用户名长度>6，拋出异常
                throw new LoginException("用户名长度必须在6位之间！");
            }
            if (conUname) {
               //如果用户名格式正确，判断密码长度
                if (user.getPassword().length() == 3) {
                //如果密码长度等于3
                    System.out.println("输入密码长度符合标准");
                } else {    // 如果密码长度不等于3，拋出异常

                    throw new LoginException("密码长度必须为 3 位！");
                }        }
        } catch(LoginException e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();//回滚
            //捕获 LoginException 异常
            System.out.println(e.getMessage());
        }
        userDao.InsertUser(user);

    }
    public String loginService(String name, String password){
        String key = FAIL_KEY + name;
        RedisAtomicInteger counter = getRedisCounter(key);

        if(counter.get() >= FAIL_TIMES) {
            stringRedisTemplate.expire(key, 1, TimeUnit.MINUTES);
            System.out.println(counter.get());
            return "您已连续输错三次密码，请1分钟之后再登录";
        }
        boolean validSuccess = userDao.getUserByUserNameAndPassword(name,password);
        if(validSuccess == false){
            counter.getAndIncrement();
            userDao.increaseLoginFailedTimes(name);
            return "登录失败" + counter+"次";
        }
        userDao.increaseLoginTimes(name);
        loginLogRedisDao.insertLoginLog(name);
        return "登录成功";
    }

    public boolean registerService(String name, String password){
        //用户名不存在，创建user，创建注册日志
        userDao.registerDao(name,password);
        registerLogDao.insertRegisterLog(name);
        return true;
    }


    @Scheduled(cron = "0 0 2 * * ?")   //每天凌晨两点触发
    public void LoginTask(){
        List<User> user = userDao.getAllUserLoginTimes();
        for (int i = 0; i < user.size(); i++) {
            loginLog2Dao.insertLoginLog2(user.get(i));
        }
    }

}


